#include "Camera.h"

/*******************************************************************
* Constructor
*******************************************************************/
Camera::Camera() :  dV( D3DXVECTOR3(0,0,1) ),
					dU( D3DXVECTOR3(0,1,0) ),
					eye( D3DXVECTOR3(0,5,-10) ),
					view( D3DXVECTOR3(0,0,1) ),
					up( D3DXVECTOR3(0,1,0) ),
					forward( D3DXVECTOR3(0,0,1) ),
					strafeRight( D3DXVECTOR3(1,0,0) ),
					heading(0),
					pitch(0)
{
	
}
/*******************************************************************
* Destructor
*******************************************************************/
Camera::~Camera()
{

}
bool Camera::initialize(HWND* hW) {
	//window handle
	hWnd = hW;
	//initialize movement toggles
	movementToggles[0] = 0;
	movementToggles[1] = 0;
	movementToggles[2] = 0;
	movementToggles[3] = 0;
	pitchrollToggles[0] = 0;
	pitchrollToggles[1] = 0;
	pitchrollToggles[2] = 0;
	pitchrollToggles[3] = 0;
	headingIncrement = D3DX_PI;///2500;
	pitchIncrement = D3DX_PI;///2500;
	//get window dimensions
	RECT rc;
    GetClientRect( *hWnd, &rc );
    UINT width = rc.right - rc.left;
    UINT height = rc.bottom - rc.top;
	D3DXMatrixIdentity(&projectionMatrix);
	D3DXMatrixIdentity(&viewMatrix);
	updateView();
    setPerspectiveProjection((float)90, (float)width/(float)height, 0.1f, 100.0f);
	return true;
}
void Camera::setPerspectiveProjection(float FOV, float aspectRatio, float zNear, float zFar)
{
	//convert FOV from degrees to radians
	FOV = FOV * (float) DEG_TO_RAD;
	D3DXMatrixPerspectiveFovLH( &projectionMatrix, FOV, aspectRatio, zNear, zFar );
}
void Camera::moveForwardOn() {
		movementToggles[0] = 1;
}
void Camera::moveBackwardOn() {
		movementToggles[1] = 1;
}
void Camera::moveRightOn() {
		movementToggles[2] = 1;
}
void Camera::moveLeftOn() {
		movementToggles[3] = 1;
}
void Camera::moveForwardOff() {
		movementToggles[0] = 0;
}
void Camera::moveBackwardOff() {
		movementToggles[1] = 0;
}
void Camera::moveRightOff() {
		movementToggles[2] = 0;
}
void Camera::moveLeftOff() {
		movementToggles[3] = 0;
}
void Camera::pitchUpOn() {
	pitchrollToggles[1] = 1;
}
void Camera::pitchDownOn() {
	pitchrollToggles[0] = 1;
}
void Camera::pitchLeftOn() {
	pitchrollToggles[3] = 1;
}
void Camera::pitchRightOn() {
	pitchrollToggles[2] = 1;
}
void Camera::pitchUpOff() {
	pitchrollToggles[1] = 0;
}
void Camera::pitchDownOff() {
	pitchrollToggles[0] = 0;
}
void Camera::pitchLeftOff() {
	pitchrollToggles[3] = 0;
}
void Camera::pitchRightOff() {
	pitchrollToggles[2] = 0;
}
D3DXMATRIX *Camera::getViewMatrix() {
	return &viewMatrix;
}
D3DXMATRIX *Camera::getProjectionMatrix() {
	return &projectionMatrix;
}
void Camera::adjustHeadingPitch( float hRad, float pRad )
{
	heading += hRad;
	pitch += pRad;
}
void Camera::updateView()
{
	//create rotation matrix
	D3DXMatrixRotationYawPitchRoll( &rotationMatrix, heading, pitch, 0 );

	//create new view and up vectors
	D3DXVec3TransformCoord( &view, &dV, &rotationMatrix );
	D3DXVec3TransformCoord( &up, &dU, &rotationMatrix );

	//create new forward and strafe vectors
	D3DXVec3Normalize( &forward, &view );
	D3DXVec3Cross( &strafeRight, &up, &view );
	D3DXVec3Normalize( &strafeRight, &strafeRight );

	//take into account eye position
	view = eye + view;

	//update view matrix
	D3DXMatrixLookAtLH( &viewMatrix, &eye, &view, &up );
}
void Camera::setPositionAndView(float x, float y, float z, float hDeg, float pDeg)
{
	//set eye coordinates
	eye.x = x;
	eye.y = y;
	eye.z = z;

	//set heading and pitch
	heading = hDeg * (float) DEG_TO_RAD;
	pitch = pDeg * (float) DEG_TO_RAD;

	//update view
	updateView();
}

/*******************************************************************
* update camera view and positiont
********************************************************************/
void Camera::update()
{
	double t = camTimer.getElapsedTimeSeconds();
	//Increment Heading and Pitch
	adjustHeadingPitch(t*((pitchrollToggles[2]*pitchIncrement)-(pitchrollToggles[3]*pitchIncrement)),t*((pitchrollToggles[0]*headingIncrement)-(pitchrollToggles[1]*headingIncrement)));
	//value clamping - keep heading and pitch between 0 and 2 pi
	if ( heading > TWO_PI ) heading -= (float) TWO_PI;
	else if ( heading < 0 ) heading = (float) TWO_PI + heading;

	if ( pitch > TWO_PI ) pitch -= (float) TWO_PI;
	else if ( pitch < 0 ) pitch = (float) TWO_PI + pitch;
	//update position - t*1.5 units
	eye +=	 t * ( movementToggles[0] - movementToggles[1] ) * 10.0f * forward +
			 t * ( movementToggles[2] - movementToggles[3] ) * 10.0f * strafeRight;
	updateView();
	camTimer.reset();
}